<?php

/**
 * @auth yxt
 * 数据结构验证
 */
class nf_validate {

    /**
     * 检查
     * @param array $arr_data  可能一维或者二维数组
     * @param string $str_action 动作insert/update
     * @param obj $obj_db 业务模型对象
     */
    static function check($arr_data, $str_action, $obj_db) {
        $arr_re = array('ret' => 1, 'reason' => 'success');
        //获取对应业务模型中配置的信息
        $arr_rules = isset($obj_db->arr_rules) ? $obj_db->arr_rules : null;
        if ($arr_rules === null) {
            $arr_re['ret'] = 0;
            $arr_re['reason'] = '$arr_rules is not set';
            return $arr_re;
        }
        //获取所有需要验证的字段
        $arr_keys = array();
        foreach ($arr_rules as $arr_v) {
            $arr_keys[] = $arr_v['key'];
        }
        $key_flag = array_rand($arr_data);
        //如果是二维数组
        if (is_array($arr_data[$key_flag])) {
            $arr_rules_key = array();
            $arr_rules_msg = array();
            foreach ($arr_rules as $arr_ruls) {
                $arr_rules_key[] = $arr_ruls['key'];
                $arr_rules_msg[$arr_ruls['key']] = $arr_ruls['msg'];
            }
            $arr_check_data = array();
            foreach ($arr_data as $arr_rows) {
                $arr_check_data = array_keys($arr_rows);
                $arr_diff = array_diff($arr_rules_key, $arr_check_data);
                if (count($arr_diff) > 0&&strtolower($str_action)=='insert') {
                    $str_msg='';
                    foreach ($arr_diff as $_dv) {
                        $str_msg.=$arr_rules_msg[$_dv] . ',';
                    }
                    $arr_ckeck_re['ret'] = 0;
                    $arr_ckeck_re['reason'] = trim($str_msg, ',');
                    return $arr_ckeck_re;
                }
            }
            foreach ($arr_data as $arr_rows) {
                foreach ($arr_rows as $str_key => $str_val) {
                    //如果有配置这个字段,而且配置的是这个动作
                    if (in_array($str_key, $arr_keys)) {
                        foreach ($arr_rules as $arr_ruls) {
                            if (!in_array($arr_ruls['action'], array('both', $str_action)) || $arr_ruls['key'] != $str_key) {
                                continue;
                            }
                            switch (strtolower($arr_ruls['type'])) {
                                case 'callback':$arr_ckeck_re = self::callback($str_val, $arr_ruls['msg'], $arr_ruls['func']);
                                    break;
                                case 'email':$arr_ckeck_re = self::email($str_val, $arr_ruls['msg']);
                                    break;
                                case 'in':$arr_ckeck_re = self::in($str_val, $arr_ruls['msg'], $arr_ruls['value']);
                                    break;
                                case 'length':$arr_ckeck_re = self::length($str_val, $arr_ruls['msg'], $arr_ruls['value']);
                                    break;
                                case 'notnull':$arr_ckeck_re = self::notnull($str_val, $arr_ruls['msg']);
                                    break;
                                case 'number':$arr_ckeck_re = self::number($str_val, $arr_ruls['msg']);
                                    break;
                                case 'regex':$arr_ckeck_re = self::regex($str_val, $arr_ruls['msg'], $arr_ruls['regex']);
                                    break;
                                case 'url':$arr_ckeck_re = self::url($str_val, $arr_ruls['msg']);
                                    break;
                                default: $arr_ckeck_re = array('ret' => 0, 'reason' => $arr_ruls['type'] . ' is not exist');
                                    break;
                            }
                            //如果有误则直接返回
                            if ($arr_ckeck_re['ret'] != 1) {
                                return $arr_ckeck_re;
                            }
                        }
                    }
                }
            }
        } else {//如果是一维数组
            $arr_rules_key = array();
            $arr_rules_msg = array();
            foreach ($arr_rules as $arr_ruls) {
                $arr_rules_key[] = $arr_ruls['key'];
                $arr_rules_msg[$arr_ruls['key']] = $arr_ruls['msg'];
            }
            $arr_check_data = array_keys($arr_data);
            $arr_diff = array_diff($arr_rules_key, $arr_check_data);
            if (count($arr_diff) > 0&&strtolower($str_action)=='insert') {
                $str_msg='';
                foreach ($arr_diff as $_dv) {
                    $str_msg.=$arr_rules_msg[$_dv] . ',';
                }
                $arr_ckeck_re['ret'] = 0;
                $arr_ckeck_re['reason'] = trim($str_msg, ',');
                return $arr_ckeck_re;
            }
            foreach ($arr_data as $str_key => $str_val) {
                //如果有配置这个字段,而且配置的是这个动作
                if (in_array($str_key, $arr_keys)) {
                    foreach ($arr_rules as $arr_ruls) {
                        if (!in_array($arr_ruls['action'], array('both', $str_action)) || $arr_ruls['key'] != $str_key) {
                            continue;
                        }
                        switch (strtolower($arr_ruls['type'])) {
                            case 'callback':$arr_ckeck_re = self::callback($str_val, $arr_ruls['msg'], $arr_ruls['func']);
                                break;
                            case 'email':$arr_ckeck_re = self::email($str_val, $arr_ruls['msg']);
                                break;
                            case 'in':$arr_ckeck_re = self::in($str_val, $arr_ruls['msg'], $arr_ruls['value']);
                                break;
                            case 'length':$arr_ckeck_re = self::length($str_val, $arr_ruls['msg'], $arr_ruls['value']);
                                break;
                            case 'notnull':$arr_ckeck_re = self::notnull($str_val, $arr_ruls['msg']);
                                break;
                            case 'number':$arr_ckeck_re = self::number($str_val, $arr_ruls['msg']);
                                break;
                            case 'regex':$arr_ckeck_re = self::regex($str_val, $arr_ruls['msg'], $arr_ruls['regex']);
                                break;
                            case 'url':$arr_ckeck_re = self::url($str_val, $arr_ruls['msg']);
                                break;
                            default: $arr_ckeck_re = array('ret' => 0, 'reason' => $arr_ruls['type'] . ' is not exist');
                                break;
                        }
                        //如果有误则直接返回
                        if ($arr_ckeck_re['ret'] != 1) {
                            return $arr_ckeck_re;
                        }
                    }
                }
            }
        }
        return $arr_re;
    }

    /**
     * 使用自定义的正则表达式进行验证
     * @param	string	$value	需要验证的值
     * @param	string	$msg	验证失败的提示消息
     * @param	string	$rules	正则表达式
     */
    static function regex($value, $msg, $rules) {
        $arr_re = array('ret' => 1, 'reason' => 'success');
        if (!preg_match($rules, $value)) {
            $arr_re['ret'] = 0;
            $arr_re['reason'] = $msg;
        }
        return $arr_re;
    }

    /**
     * 非空验证
     * @param	string	$value	需要验证的值
     * @param	string	$msg	验证失败的提示消息
     */
    static function notnull($value, $msg) {
        $arr_re = array('ret' => 1, 'reason' => 'success');
        if (!empty($value)) {
            $value = trim($value);
        }
        if (strlen($value) == 0) {
            $arr_re['ret'] = 0;
            $arr_re['reason'] = $msg;
        }
        return $arr_re;
    }

    /**
     * Email格式验证
     * @param	string	$value	需要验证的值
     * @param	string	$msg	验证失败的提示消息
     */
    static function email($value, $msg) {
        $arr_re = array('ret' => 1, 'reason' => 'success');
        $rules = "/\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/";
        if (!preg_match($rules, $value)) {
            $arr_re['ret'] = 0;
            $arr_re['reason'] = $msg;
        }
        return $arr_re;
    }

    /**
     * URL格式验证
     * @param	string	$value	需要验证的值
     * @param	string	$msg	验证失败的提示消息
     */
    static function url($value, $msg) {
        $arr_re = array('ret' => 1, 'reason' => 'success');
        $rules = '/^http\:\/\/([\w-]+\.)+[\w-]+(\/[\w-.\/?%&=]*)?$/';
        if (!preg_match($rules, $value)) {
            $arr_re['ret'] = 0;
            $arr_re['reason'] = $msg;
        }
        return $arr_re;
    }

    /**
     * 数字格式验证
     * @param	string	$value	需要验证的值
     * @param	string	$msg	验证失败的提示消息
     */
    static function number($value, $msg) {
        $arr_re = array('ret' => 1, 'reason' => 'success');
        $rules = '/^\d+$/';
        if (!preg_match($rules, $value)) {
            $arr_re['ret'] = 0;
            $arr_re['reason'] = $msg;
        }
        return $arr_re;
    }

    /**
     * 使用回调用函数进行验证
     * @param	string	$value	需要验证的值
     * @param	string	$msg	验证失败的提示消息
     * @param	string	$rules	回调函数名称，回调用函数写在commons下的common.fun.inc.php
     */
    static function callback($value, $msg, $rules) {
        $arr_re = array('ret' => 1, 'reason' => 'success');
        if (!call_user_func_array($rules, array($value))) {
            $arr_re['ret'] = 0;
            $arr_re['reason'] = $msg;
        }
        return $arr_re;
    }

    /**
     * 验证数据的值是否在一定的范围内
     * @param	string	$value	需要验证的值
     * @param	string	$msg	验证失败的提示消息
     * @param	string	$rules	一个值或多个值，或一个范围
     */
    static function in($value, $msg, $rules) {
        $arr_re = array('ret' => 1, 'reason' => 'success');
        //多个值使用的是逗号分隔
        if (strstr($rules, ",")) {
            if (!in_array($value, explode(",", $rules))) {
                $arr_re['ret'] = 0;
                $arr_re['reason'] = $msg;
            }
        } else if (strstr($rules, '-')) {//多个值使用的是-分隔
            list($min, $max) = explode("-", $rules);
            if (!($value >= $min && $value <= $max)) {
                $arr_re['ret'] = 0;
                $arr_re['reason'] = $msg;
            }
        } else {//确定
            if ($rules != $value) {
                $arr_re['ret'] = 0;
                $arr_re['reason'] = $msg;
            }
        }
        return $arr_re;
    }

    /**
     * 验证数据的值的长度是否在一定的范围内
     * @param	string	$value	需要验证的值
     * @param	string	$msg	验证失败的提示消息
     * @param	string	$rules	一个范围，例如 3-20(3-20之间)、3,20(3-20之间)、3(必须是3个)、3,(3个以上)
     */
    static function length($value, $msg, $rules) {
        $arr_re = array('ret' => 1, 'reason' => 'success');
        $fg = strstr($rules, '-') ? "-" : ",";

        if (!strstr($rules, $fg)) {
            if (strlen($value) != $rules) {
                $arr_re['ret'] = 0;
                $arr_re['reason'] = $msg;
            }
        } else {

            list($min, $max) = explode($fg, $rules);

            if (empty($max)) {
                if (strlen($value) < $rules) {
                    $arr_re['ret'] = 0;
                    $arr_re['reason'] = $msg;
                }
            } else if (!(strlen($value) >= $min && strlen($value) <= $max)) {
                $arr_re['ret'] = 0;
                $arr_re['reason'] = $msg;
            }
        }
        return $arr_re;
    }

}
